//TODO: Logic should be fixed so that, when not IE, the jQuery History thing will work and will still allow one to select items for a search and have the selection actually work....
var browserIsIE = true //window.navigator.userAgent.indexOf("MSIE ") < 0 ? false : true;
var map;
var overview_width;
var overview_height;
var resolution_meters_per_pixel;
var center_longitude;
var center_latitude;
var current_body;
var current_projection = "ORTHO";
var radius;
var feature_fetcher;
var active_tasks = [];
var cursor_string = "";
var url_array = null;
var scale_bar_length = 200;
var lat_err = false;
var lon_err = false;
var configuration;
var layer_group_visibility;
var persistent_additional_wms = [];
var external_container;
var bBoxDrawingControl = null;
var tour = null;
var mdsParams = null;
var onlyOneBaseLayer = false;
var layer_desciption = {};//地图选项、图层、概览视图的描述

function init_tour() {
	tour = new Tour({
		steps: [
			{
				orphan: true,
				title: "操作指引",
				content: "欢迎！本操作指引将会带你熟悉基本的操作。在你关闭后，该指引将不再显示。如果你需要再次显示该指引，请点击页面的“使用教程”。"
			},
			{
				placement: 'left',
				element: "#point-of-interest",
				title: "Recenter the Map",
				content: "The target icon activates the recentering mouse tool.  This will either pan the map to the position clicked on, or reproject the map with that as the center depending on the selected view."
			},
			{
				placement: 'left',
				element: "#get-footprint",
				title: "Get Footprint Information",
				content: "With the 'eye' icon selected, click on a point or footprint drawn on the map for more information on features at that point."
			},
			{
				placement: 'left',
				element: "#bounding-box",
				title: "Bounding Box Search",
				content: "The dashed-box icon allows you to draw a box on the map to search for all features overlapped by the box."
			},
			{
				placement: 'top',
				element: "#scale_bar",
				title: "鼠标位置坐标和比例尺",
				content: "这块区域显示了投影中心的比例尺，你鼠标所在位置的经纬度坐标。"
			},
			{
				placement: 'bottom',
				element: "#hamburger",
				title: "主菜单",
				content: "点击这里进入地图服务的菜单选项. 你可以在这里选择多种地图的投影方式，并获得当前视图的分享链接。你可以显示或关闭不同的图层。概览视图中的红色方框代表主视图的范围。点击概览视图中的任意位置，可以让地图以你点击的位置为投影中心进行新的投影。"
			},
			{
				placement: 'bottom',
				element: "#help",
				title: "鼠标操作",
				content: "1、单击：主菜单勾选地名信息后，鼠标单击地图上的地名，弹出地名信息框。<br>" +
				"2、双击：双击地图上的任意位置，可以让地图以你双击的位置为投影中心进行新的投影。<br>" +
				"3、滚轮：地图放大缩小。<br>" +
				"4、拖拽：按住鼠标左键，拖动地图。"
			}
		]
	});
	tour._scrollIntoView = function (e, c) { return c(); };
	tour.init();
}

function show_tour() {
	tour.restart();
}

function invoke_recenter() {
	if (!(lat_err || lon_err)) {
		recenter(document.getElementById('lunaserv_lon_c').value, document.getElementById('lunaserv_lat_c').value, true, true);
	}
}

function checkNumeric(event) {
	var ascii = event.which;
	if (ascii == 13) {
		// Trigger validity checks
		jQuery('#lunaserv_lon_c').blur();
		jQuery('#lunaserv_lat_c').blur();
		// Hit the button
		jQuery('#lunaserv_recenter_button').click();
	}
	if (ascii >= 32 && ascii <= 42) event.preventDefault();
	if (ascii == 44) event.preventDefault();
	if (ascii == 47) event.preventDefault();
	if (ascii >= 58 && ascii <= 126) event.preventDefault();
}

function check_for_url_parameter(param_name) {
	param_name = param_name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
	var regexS = "[\\?&]" + param_name + "=([^&#]*)";
	var regex = new RegExp(regexS);
	var results = regex.exec(window.location.href);
	if (results == null) return "";
	else return decodeURIComponent(results[1]);
}

function round_number(num, dec) {
	return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

function apply_date_range() {
	persistent_additional_wms["STARTDATE"] = jQuery("input[name='start']").val().length ? jQuery("input[name='start']").val() : null;
	persistent_additional_wms["ENDDATE"] = jQuery("input[name='end']").val().length ? jQuery("input[name='end']").val() : null;

	for (var i = 0; i < layers.length; i++) {
		layers[i].mergeNewParams(persistent_additional_wms);
	}
}

function apply_mds_search(mdsSearch) {
	for (var i = 0; i < layers.length; i++) {
		layers[i].mergeNewParams({ "MDS_SEARCH": mdsSearch });
	}
}

// Go from lon/lat in degrees to location in projection
function project(geo_location) {
	var longitude = geo_location.lon;
	var latitude = geo_location.lat;
	longitude = valid_longitude(longitude);
	if (latitude > 90 || latitude < -90) return { lon: NaN, lat: NaN };
	// To radians for math functions
	longitude = longitude * 3.14159 / 180;
	latitude = latitude * 3.14159 / 180;
	var center_longitude_rads = center_longitude * 3.14159 / 180;
	var center_latitude_rads = center_latitude * 3.14159 / 180;
	var x, y;
	// Perform the conversion depending on the projection
	if (current_projection == "ORTHO") {
		x = radius * Math.cos(latitude) * Math.sin(longitude - center_longitude_rads);
		y = radius * (Math.cos(center_latitude_rads) * Math.sin(latitude) - Math.sin(center_latitude_rads) * Math.cos(latitude) * Math.cos(longitude - center_longitude_rads));
	}
	if (current_projection == "SINU") {
		x = radius * (longitude - center_longitude_rads) * Math.cos(latitude);
		y = radius * latitude;
	}
	if (current_projection == "NP_STEREO" || current_projection == "SP_STEREO") {
		if (current_projection == "SP_STEREO") longitude = -longitude;
		var rads_away_from_pole = (current_projection == "NP_STEREO" ? 3.14159 / 2 - latitude : 3.14159 / 2 + latitude);
		var theta = longitude - (current_projection == "NP_STEREO" ? 3.14159 / 2 : - 3.14159 / 2);
		var R = 2 * radius / Math.tan((3.14159 - rads_away_from_pole) / 2);
		// Special case
		if (rads_away_from_pole == 0) R = 0;
		x = R * Math.cos(theta);
		y = R * Math.sin(theta);
	}
	if (current_projection == "2000") {
		// 2000 is measured in lon/lat
		x = longitude * 180 / 3.14159;
		y = latitude * 180 / 3.14159;
	}
	return { lon: x, lat: y };
}

// Go from a location in the projection to a lon/lat in degrees
function unproject(mouse_location) {
	if (mouse_location) {
		var x = mouse_location.lon;
		var y = mouse_location.lat;
		// To radians for math functions
		var center_longitude_rads = center_longitude * 3.14159 / 180;
		var center_latitude_rads = center_latitude * 3.14159 / 180;
		var longitude;
		var latitude;
		// Perform the conversion depending on the projection
		if (current_projection == "ORTHO") {
			var rho = Math.sqrt(x * x + y * y);
			var c = Math.asin(rho / radius);
			longitude = center_longitude_rads + Math.atan2(x * Math.sin(c), rho * Math.cos(center_latitude_rads) * Math.cos(c) - y * Math.sin(center_latitude_rads) * Math.sin(c));
			latitude = Math.asin(Math.cos(c) * Math.sin(center_latitude_rads) + (y * Math.sin(c) * Math.cos(center_latitude_rads) / rho));
			// Special case
			if (rho == 0) latitude = center_latitude_rads;
		}
		if (current_projection == "SINU") {
			latitude = y / radius;
			longitude = (x / radius) / Math.cos(latitude) + center_longitude_rads;
			// Since we're in sinusoidal, which bogusly repeats, reproject the unprojection back into the image, and see if this spot is authentic
			// But first, we must normalize our lon/lat to between -180 / 180 (away from center!!) and -90 / 90, respectively
			while (longitude > 3.14159 + center_longitude_rads) longitude -= 3.14159;
			while (longitude < -3.14159 + center_longitude_rads) longitude += 3.14159;
			while (latitude > 3.14159 / 2) latitude -= 3.14159 / 2;
			while (latitude < -3.14159 / 2) latitude += 3.14159 / 2;
			var test_x = (longitude - center_longitude_rads) * radius * Math.cos(latitude);
			var test_y = latitude * radius;
			if (Math.abs(test_x - x) > 0.01 || Math.abs(test_y - y) > 0.01) return { lon: NaN, lat: NaN };
		}
		if (current_projection == "NP_STEREO" || current_projection == "SP_STEREO") {
			var R = Math.sqrt(x * x + y * y);
			var rads_away_from_pole = 3.14159 - 2 * Math.atan((2 * radius) / R);
			// Special case
			if (R == 0) rads_away_from_pole = 0;
			latitude = (current_projection == "NP_STEREO" ? 3.14159 / 2 - rads_away_from_pole : - 3.14159 / 2 + rads_away_from_pole);
			longitude = Math.atan2(y, x) + (current_projection == "NP_STEREO" ? 3.14159 / 2 : - 3.14159 / 2);
			if (current_projection == "SP_STEREO") longitude = -longitude;
		}
		if (current_projection == "2000") {
			// 2000 is measured in lon/lat already
			longitude = x;
			latitude = y;
			// But make sure we aren't beyond the map boundary
			if (longitude < -180 || longitude > 180 || latitude < -90 || latitude > 90) return { lon: NaN, lat: NaN };
			return { lon: longitude, lat: latitude };
		}
		// Back to degrees
		longitude *= 180 / 3.14159;
		latitude *= 180 / 3.14159;
		return { lon: longitude, lat: latitude };
	}
	else return { lon: NaN, lat: NaN };
}

// Distance in meters on the current planetary body from one latlon to another
function arc_length_meters(a, b) {
	// To radians for math functions
	a.lon *= 3.14159 / 180;
	a.lat *= 3.14159 / 180;
	b.lon *= 3.14159 / 180;
	b.lat *= 3.14159 / 180;
	// Haversine formula
	return radius * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin((b.lat - a.lat) / 2), 2) + Math.cos(a.lat) * Math.cos(b.lat) * Math.pow(Math.sin((b.lon - a.lon) / 2), 2)));
}

function recenter(lon_c, lat_c, persist_layers, persist_zoom_level, body, projection) {
	var failed_to_maintain_location = false;
	var geo_location = { lon: lon_c, lat: lat_c };
	var different_body = (body && (body != current_body));
	if (different_body) current_body = body;
	if (projection) current_projection = projection;
	var zoom_level;
	var selected_basemap_index;
	var overlay_visibilities = [];
	var selected_layer_controls = [];
	if (persist_layers) {
		for (layer = 0; layer < map.getNumLayers(); layer++) {
			if (!map.layers[layer].isBaseLayer) overlay_visibilities.push(map.layers[layer].getVisibility());
			if (!map.layers[layer].alwaysInRange) { // Exclude the bbox drawing layer
				selected_layer_controls.push(document.getElementById("lunaserv_switch_" + map.layers[layer].unique_id).checked);
			}
		}
	}
	if (persist_zoom_level) zoom_level = map.getZoom();
	map.destroy();
	if (current_projection == "ORTHO") {
		init(lon_c, lat_c, different_body);
	}
	if (current_projection == "SINU") {
		init(lon_c, 0, different_body);
		map.setCenter(new OpenLayers.LonLat(0, project(geo_location).lat));
	}
	if (current_projection == "NP_STEREO" || current_projection == "SP_STEREO" || current_projection == "2000") {
		init(0, 0, different_body);
		var place = new OpenLayers.LonLat(project(geo_location).lon, project(geo_location).lat);
		map.setCenter(place);
		if (place.lon > map.getMaxExtent().right || place.lon < map.getMaxExtent().left || place.lat > map.getMaxExtent().top || place.lat < map.getMaxExtent().bottom) failed_to_maintain_location = true;
	}
	if (persist_layers) {
		for (layer = 0; layer < map.getNumLayers(); layer++) {
			if (!map.layers[layer].isBaseLayer) map.layers[layer].setVisibility(overlay_visibilities.shift());
			if (!map.layers[layer].alwaysInRange) { // Exclude the bbox drawing layer
				document.getElementById("lunaserv_switch_" + map.layers[layer].unique_id).checked = selected_layer_controls.shift();
			}
		}
	}
	refresh_layer_visibilities();
	if (persist_zoom_level) {
		// Special case: if we're switching to stereographic, only persist the zoom level if we were able to keep looking at the same spot; otherwise, zoom all the way back out
		if (!failed_to_maintain_location) map.zoomTo(zoom_level);
	}
	update_permalink();
}

function valid_longitude(lon) {
	while (lon > 180) lon -= 360;
	while (lon < -180) lon += 360;
	return lon;
}

function mouse_move(event) {
	var mouse_location = map.getLonLatFromPixel(new OpenLayers.Pixel(this.events.getMousePosition(event).x, this.events.getMousePosition(event).y));
	var geo_location = unproject(mouse_location);
	jQuery("#lunaserv_mouse_lat").html((isNaN(geo_location.lat) ? "---" : round_number(geo_location.lat, 3)));
	jQuery("#lunaserv_mouse_lon").html((isNaN(geo_location.lon) ? "---" : round_number(valid_longitude(geo_location.lon), 3)));
}

// This function updates the permalink target and should be called after every change (simple map movement including panning/zooming; layer toggling; reprojection)
function update_permalink() {
	var current_bbox = map.getExtent();
	var permalink = document.getElementById("lunaserv_permalink");
	permalink.href = document.URL.substr(0, document.URL.indexOf("?") == -1 ? document.URL.length : document.URL.indexOf("?")) + "?";
	permalink.href += "projection=" + current_projection;
	permalink.href += "&c_lon=" + center_longitude;
	permalink.href += "&c_lat=" + center_latitude;
	permalink.href += "&x=" + ((current_bbox.left + current_bbox.right) / 2);
	permalink.href += "&y=" + ((current_bbox.top + current_bbox.bottom) / 2);
	permalink.href += "&resolution=" + (map.getResolution());
	permalink.href += "&layers=";
	for (var i = 0; i < map.layers.length; i++) {
		if (map.layers[i].getVisibility() && map.layers[i].unique_id) permalink.href += map.layers[i].unique_id + ",";
	}
	if (permalink.href.charAt(permalink.href.length - 1) == ',') permalink.href = permalink.href.substr(0, permalink.href.length - 1);
	// Default to the Moon, and only specify if not the Moon, so that the planet-switching capability is invisible apart from the dropdown box
	if (current_body != "MOON") permalink.href += "&body=" + current_body;
}

function update_overview_box() {
	var current_bbox = map.getExtent();
	var maximum_bbox = map.getMaxExtent();
	var overview_map = document.getElementById('lunaserv_overview_map');
	var overview_box = document.getElementById('lunaserv_overview_box');
	var width_of_overview_box = overview_width * (current_bbox.right - current_bbox.left) / (maximum_bbox.right - maximum_bbox.left);
	var height_of_overview_box = overview_height * (current_bbox.top - current_bbox.bottom) / (maximum_bbox.top - maximum_bbox.bottom);
	var top_of_overview_box = overview_height * ((current_bbox.top - maximum_bbox.top) / (maximum_bbox.bottom - maximum_bbox.top));
	var left_of_overview_box = overview_width * ((current_bbox.left - maximum_bbox.left) / (maximum_bbox.right - maximum_bbox.left));
	overview_box.style.left = "" + left_of_overview_box + "px";
	overview_box.style.top = "" + top_of_overview_box + "px";
	overview_box.style.width = "" + width_of_overview_box + "px";
	overview_box.style.height = "" + height_of_overview_box + "px";
}

function update_resolution() {
	// Take two spots in the center; space them out by a total distance equal to the scale bar's length
	var x1 = (map.minPx.x + map.maxPx.x) / 2;
	var y1 = (map.minPx.y + map.maxPx.y) / 2;
	x1 -= scale_bar_length / 2;
	var x2 = (map.minPx.x + map.maxPx.x) / 2;
	var y2 = (map.minPx.y + map.maxPx.y) / 2;
	x2 += scale_bar_length / 2;
	// Get their coordinates in the projection
	var place1 = map.getLonLatFromPixel(new OpenLayers.Pixel(x1, y1));
	var place2 = map.getLonLatFromPixel(new OpenLayers.Pixel(x2, y2));
	// Unproject to latlon
	var latlon1 = unproject(place1);
	var latlon2 = unproject(place2);
	var distance_meters = arc_length_meters(latlon1, latlon2);
	var distance_kilometers = distance_meters / 1000;
	jQuery("#lunaserv_scaletext").html("" + (distance_meters >= 5000 ? round_number(distance_kilometers, 2) + "km" : round_number(distance_meters, 2) + "m") + " (在投影中心)");
	// Update global variable
	resolution_meters_per_pixel = distance_meters / scale_bar_length;
}

function map_move(event) {
	// Update the current meters-per-pixel resolution
	update_resolution();
	// Check and see if there are any restricted-resolution layers that need to be updated
	for (var i = 0; i < map.layers.length; i++) {
		if (map.layers[i].minimum_resolution) {
			if (resolution_meters_per_pixel > map.layers[i].minimum_resolution) {
				// This layer is unavailable right now, so make sure it is unchecked, unselectable, and disabled
				document.getElementById("lunaserv_switch_" + map.layers[i].unique_id).checked = false;
				map.layers[i].setVisibility(false);
				document.getElementById("lunaserv_switch_" + map.layers[i].unique_id).disabled = true;
			}
			else {
				// This layer is available, so ensure it is selectable
				document.getElementById("lunaserv_switch_" + map.layers[i].unique_id).disabled = false;
			}
		}
	}
	// Other things that may need updating
	update_overview_box();
	update_permalink();
}

function setUpFeatureFetcher() {
	var found_a_queryable_layer = false;
	/* IMPORTANT: This feature-fetching routine is constructed specially to make one request for all queryable layers,
	 * including accounting for the custom parameters which filter the LROC and Apollo footprint layers.  It assumes
	 * that the additional custom parameters (currently {NAC|WAC}_PHASE, {METRIC|PAN}_MISSION, {METRIC|PAN}_REVOLUTION)
	 * for all visible and queryable layers can properly sit together in one request and the server will still return
	 * what the user expects; if the layer-filtering/displaying scheme does not conform to that, then this will not
	 * give the expected results.
	 *
	 * --changer@ser.asu.edu
	 *
	 */
	feature_fetcher.layers = [];
	feature_fetcher.vendorParams = {};
	for (var i = 0; i < map.layers.length; i++) {
		if (map.layers[i].getVisibility() && map.layers[i].queryable) {
			found_a_queryable_layer = true;
			feature_fetcher.layers.unshift(map.layers[i]);
			for (var parameter in map.layers[i].additional_wms) {
				feature_fetcher.vendorParams[parameter] = map.layers[i].additional_wms[parameter];
			}
			if (jQuery("input[name='start']").val().length) feature_fetcher.vendorParams["STARTDATE"] = jQuery("input[name='start']").val();
			if (jQuery("input[name='end']").val().length) feature_fetcher.vendorParams["ENDDATE"] = jQuery("input[name='end']").val();
			if (check_for_url_parameter('MDS_SEARCH').length) feature_fetcher.vendorParams["MDS_SEARCH"] = check_for_url_parameter('MDS_SEARCH');
		}
	}
	if (!found_a_queryable_layer) alert("Cannot query for footprint info because no queryable layers are turned on.");
	return (found_a_queryable_layer);
}

function click(event) {
	// The map_move event handler is slightly buggy in conjunction with the "kinetic dragging", so we make sure to call map_move on every click
	map_move(null);
	switch (jQuery('input[name="lunaserv_click_mode"]:checked').val()) {
		case "recenter":
			var new_location = map.getLonLatFromPixel(event.xy);
			var coords = unproject(new_location);
			if (!isNaN(coords.lon) && !isNaN(coords.lat)) {
				recenter(valid_longitude(coords.lon), coords.lat, true, true);
			}
			break;

		case "zoom":
			map.zoomIn();
			break;

		case "feature":
			if (active_tasks.indexOf("get_feature") != -1) return; // Have some patience, I'm not finished with the last point you queried!

			if (setUpFeatureFetcher()) {
				document.getElementById("lunaserv_map").style.cursor = "wait";
				active_tasks.push("get_feature");
				try {
					feature_fetcher.request(event.xy);
				}
				catch (err) {
					alert("There was an error when requesting features.  A likely cause is that your web browser does not accept cross-domain XML data sharing.");
					active_tasks.splice(active_tasks.indexOf("get_feature"), 1);
					if (active_tasks.length == 0) document.getElementById("lunaserv_map").style.cursor = cursor_string;
				}
			}
			break;

		case "bounding-box":
			if (active_tasks.indexOf("get_bBox") != -1) return; // Have some patience, I'm not finished with the last point you queried!

			if (setUpFeatureFetcher()) {
				feature_fetcher.vendorParams['SEARCH_BBOX'] =
					event.feature.geometry.bounds.left + ',' +
					event.feature.geometry.bounds.bottom + ',' +
					event.feature.geometry.bounds.right + ',' +
					event.feature.geometry.bounds.top;
				document.getElementById("lunaserv_map").style.cursor = 'wait';
				active_tasks.push("get_bBox");
				try {
					feature_fetcher.request({
						x: event.object.callbacks.done.caller.arguments[1][0].x,
						y: event.object.callbacks.done.caller.arguments[1][0].y
					});
				}
				catch (err) {
					alert("There was an error when requesting features.  A likely cause is that your web browser does not accept cross-domain XML data sharing.");
					active_tasks.splice(active_tasks.indexOf("get_feature"), 1);
					if (active_tasks.length == 0) document.getElementById("lunaserv_map").style.cursor = cursor_string;
				}
			}
			var bBoxLayer = map.getLayersByName('Box layer');
			setTimeout(function () { bBoxLayer[0].removeAllFeatures() }, 2000);
		//                var wkt = new OpenLayers.Format.WKT();
		//                console.info(wkt.write(event.feature));
	}
}

function queryResultHeaderScrolling(e) {
	//        var tow = Math.round(jQuery('#lunaserv_selected_footprints').offset().top + 1); //top of scrollable window
	var tow = jQuery('#lunaserv_features_titlebar').height();
	var hh = jQuery('.lunaserv_layer_name').height(); //Height of category heading
	console.info('container: ' + jQuery('#lunaserv_feature_container').height() + ' titlebar: ' + jQuery('#lunaserv_features_titlebar').height());
	jQuery('#lunaserv_selected_footprints').height(jQuery('#lunaserv_feature_container').height() - jQuery('#lunaserv_features_titlebar').height());
	jQuery('#lunaserv_selected_footprints .lunaserv_layer').each(function () {
		if (jQuery(this).position().top < tow && jQuery(this).position().top + jQuery(this).height() + hh > tow) {
			// the following line of code can replace the next 'live' one if we can figure out a way to make it not go over the top edge of the window.  
			//                        var offSet = tow - (jQuery(this).position().top + jQuery(this).height() - hh);
			//                        jQuery(this).find('.lunaserv_layer_name').css('position', 'absolute').css('top', Math.round(tow - (offSet > 0 ? offSet : 0) + 1)).width(jQuery('#lunaserv_selected_footprints').width());
			jQuery(this).find('.lunaserv_layer_name').css('position', 'absolute').css('top', tow).width(jQuery('#lunaserv_selected_footprints').innerWidth());
		}
		else {
			jQuery(this).find('.lunaserv_layer_name').css('position', 'static').width(jQuery('#lunaserv_selected_footprints').innerWidth());
		}
	});
}

function getNameByServerLayers(sl) {
	for (var i = 0; i < map.layers.length; i++) {
		if (!(map.layers[i].params.LAYERS === 'undefined') && map.layers[i].params.LAYERS === sl) return (map.layers[i]);
	}
	console.log('getNameByServerLayers could not find SERVER_LAYERS = "' + sl + '"');
	return ('null');
}

function show_info(e) {
	active_tasks.splice(active_tasks.indexOf("get_feature" || "get_bBox"), 1);
	if (active_tasks.length == 0) document.getElementById("lunaserv_map").style.cursor = cursor_string;
	jQuery("#lunaserv_selected_footprints").animate({ scrollTop: 0 }, "slow");
	jQuery("#lunaserv_selected_footprints").html(e.text);
	jQuery('#lunaserv_selected_footprints .lunaserv_nodata').remove();
	if (jQuery('#lunaserv_selected_footprints .lunaserv_feature_info').length) {
		jQuery('#lunaserv_selected_footprints .lunaserv_layer_name').each(function () {
			var layerObj = getNameByServerLayers(jQuery(this).html());
			jQuery(this).html(layerObj.name + ' (' + jQuery(this).next('.lunaserv_features').find('.lunaserv_feature_info').length + ')').css('background', '#' + layerObj.legend_color);
		});
		jQuery('.lunaserv_features').append('<div class="clearfix"></div>');
		jQuery('#lunaserv_selected_footprints').scroll(queryResultHeaderScrolling);
		jQuery('#lunaserv_feature_container').css('top', (Math.round(jQuery(window).height() - jQuery('#lunaserv_feature_container').height()) / 2) + 'px')
			.css('left', (Math.round(jQuery(window).width() - jQuery('#lunaserv_feature_container').width()) / 2) + 'px');
		jQuery("#lunaserv_feature_container").show();
		jQuery('#lunaserv_selected_footprints').height(jQuery('#lunaserv_feature_container').height() - jQuery('#lunaserv_features_titlebar').height());
	}
	else {
		alert("No results were found at that location.");
	}
}

// Note: A "layer" may be added which isn't really a layer (so that a control will show up in the control box,
// nominally for disabling all of the layers in a radio button group) by passing true for "phony"
function add_layer(layers, unique_id, display_name, is_base_layer, name_on_server, additional_wms, queryable, radio_group, phony, start_out_selected, minimum_resolution, depth, refresh_seconds, legend_color) {
	wms_options = { layers: name_on_server, format: 'image/png', transparent: 'true' };
	if (additional_wms) for (attr in additional_wms) wms_options[attr] = additional_wms[attr];
	// When fully zoomed out, radius should occupy 500 pixels on the screen.
	// We set the non-base-layers to a bigger number to ensure that they always
	// show up.
	var maxResolution = (is_base_layer ? radius / 500 : radius / 400);
	// When fully zoomed in, use 1m/px.  We set the non-base-layers to a
	// smaller number to ensure that they always show up.
	var minResolution = (is_base_layer ? 1 : 0.5);
	// If the current projection is 2000, which is defined in lat/lon, we need
	// to convert our resolutions to match.
	if (current_projection == "2000") {
		maxResolution /= radius * (3.14159 / 180);
		minResolution /= radius * (3.14159 / 180);
	}
	var this_layer = new OpenLayers.Layer.WMS(
		display_name,
		url_array,
		wms_options,
		{ buffer: 0, transitionEffect: (is_base_layer ? "resize" : "none"), maxResolution: maxResolution, minResolution: minResolution, numZoomLevels: 20, unique_id: unique_id, isBaseLayer: is_base_layer, queryable: queryable, visibility: false, radio_group: radio_group, phony: phony, start_out_selected: start_out_selected, minimum_resolution: minimum_resolution, tileOrigin: new OpenLayers.LonLat(0, 0), legend_color: legend_color }
	);
	this_layer.additional_wms = {};
	if (depth) this_layer.depth = parseInt(depth);
	for (var parameter in additional_wms) {
		this_layer.additional_wms[parameter] = additional_wms[parameter];
	}
	if (refresh_seconds > 0) {
		setInterval(function () { this_layer.redraw(true); }, refresh_seconds * 1000);
	}
	layers.push(this_layer);
}

function toggle_layer_group_visibility(id) {
	// Change variable
	layer_group_visibility[id] = !layer_group_visibility[id];
	// Show or hide the contents of the appropriate list
	document.getElementById("lunaserv_layer_group_" + id).style.display = (layer_group_visibility[id] ? "" : "none");
	// Write (-) or (+) accordingly
	jQuery("#lunaserv_layer_group_toggler_" + id).html((layer_group_visibility[id] ? '(-) ' : '(+) '));
}

function legend_add(text, color) {
	jQuery('#lunaserv_layer_legend').append('<li>' + '<div class="legend" style="background-color: ' + color + '; margin-left: 0px;"></div>' + text + '</li>');
}

function legend_remove_all() {
	jQuery('#lunaserv_layer_legend li').remove();
}

function legend_update() {
	legend_remove_all();
	jQuery('.legend').prev(':checked').each(function () { // This gets the legend text and color of dot from the menu so be careful when changing menu html, etc.
		legend_add(jQuery(this).parent().text(), jQuery(this).next().css('background-color'));
	});
}

function refresh_layer_visibilities() {
	for (var i = 0; i < map.layers.length; i++) {
		if (map.layers[i].isBaseLayer && document.getElementById("lunaserv_switch_" + map.layers[i].unique_id).checked) map.setBaseLayer(map.layers[i]);
		if (!(map.layers[i].isBaseLayer) && !(map.layers[i].phony) && !(map.layers[i].alwaysInRange)) {
			var visibility = map.layers[i].getVisibility();
			var new_visibility = document.getElementById("lunaserv_switch_" + map.layers[i].unique_id).checked;
			if (visibility != new_visibility) map.layers[i].setVisibility(new_visibility);
		}
	}
	// Now that the layers have changed, the legend and permalink should change as well
	legend_update();
	update_permalink();
	showHideDateRange();
}

function showHideDateRange() {
	var dateSearch = false;
	for (var i = 0; i < layers.length; i++) {
		if (layers[i].getVisibility() == true) {
			var layersToSearch = configuration["BODIES"][current_body]["LAYERS"]["ISS"];
			for (var lyr in layersToSearch) {
				if (layersToSearch[lyr].NAME == layers[i].name) {
					if (layersToSearch[lyr].SEARCHABLEBYDATE == "YES") {
						dateSearch = true;
					}
				}
			}
		}
	}
	if (dateSearch == true) {
		document.getElementById("dateRange").style.display = "inline";
	} else {
		document.getElementById("dateRange").style.display = "none";
	}
}

function build_legend(layer) {
	var color = "";
	if ("LEGEND_COLOR" in layer) {
		color = '<div class="legend" style="background-color: #' + layer["LEGEND_COLOR"] + '"></div>';
	}
	return color;
}

function onlyOneOptionForLayer(layer) {
	var i = 0;
	for (var property in layer) {
		// Descend into contained objects and add them
		if (typeof (layer[property]) == "object") i++;
	}
	return i == 1 ? true : false;
}

function load_layer(layers, layer_id, layer, reconstructing) {
	if (layer["TYPE"] == "MENU") {
		// This is actually a menu of layers
		if (reconstructing) {
			// Add the list expander/collapser to the dialog
			html_string += '<div id="lunaserv_layer_group_label_' + layer_id + '" class=lunaserv_layer_group_label onclick="toggle_layer_group_visibility(\'' + layer_id + '\');">';
			html_string += '<span id="lunaserv_layer_group_toggler_' + layer_id + '" class="lunaserv_mono">' + (layer_group_visibility[layer_id] ? '(-) ' : '(+) ') + '</span>' + layer["NAME"];
			html_string += "</div>";
			// Add the beginning of the group to the dialog
			html_string += '<div class="lunaserv_layer_group" id="lunaserv_layer_group_' + layer_id + '"' + (layer_group_visibility[layer_id] ? '' : 'style="display:none;"') + '>';
			// Add the variable keeping track of whether or not this list is being shown
			layer_group_visibility[layer_id] = false;
		}
		if (layer['NAME'] == 'Base layer' && onlyOneOptionForLayer(layer)) onlyOneBaseLayer = true;
		for (var property in layer) {
			// Descend into contained objects and add them
			if (typeof (layer[property]) == "object") load_layer(layers, property, layer[property], reconstructing);
		}
		if (reconstructing) {
			// Add the end of the layer group to the dialog
			html_string += "</div>";
		}
	}
	else {
		// This is not a menu, so we add a "layer" for it (whether it's truly a layer or just a "phony layer", such as a disabler)
		if (reconstructing) {
			if (onlyOneBaseLayer) {
				html_string += '<span id="lunaserv_switch_' + layer_id + '">Single Base Layer: ' + layer["NAME"] + '</span>';
				onlyOneBaseLayer = false;
			}
			else {
				// Add the switcher for this layer to the dialog box
				html_string += '<label><input id="lunaserv_switch_' + layer_id + '" ';
				if (layer["TYPE"] == "RADIO") html_string += 'type="radio" name="' + layer["RADIO_GROUP"] + '" ';
				if (layer["TYPE"] == "CHECKBOX") html_string += 'type="checkbox" ';
				html_string += 'onclick="refresh_layer_visibilities();" ';
				// Two types of selectors should start out checked: the default basemap for the body, and those which do not actually turn on any server layers ("disable" controls)
				html_string += (((!layer["SERVER_LAYERS"]) || layer["SERVER_LAYERS"] == configuration["BODIES"][current_body]["DEFAULT_BASEMAP"]) ? "checked " : "");
				html_string += '/ >' + layer["NAME"] + build_legend(layer) + "</label><br>";
				html_string += add_layer_desc(layer);
			}
		}
		add_layer(layers, layer_id, layer["NAME"], (layer["RADIO_GROUP"] ? (layer["RADIO_GROUP"] == "BASE") : false), (layer["SERVER_LAYERS"] ? layer["SERVER_LAYERS"] : null), (layer["ADDITIONAL_WMS"] ? layer["ADDITIONAL_WMS"] : null), (layer["QUERYABLE"] ? (layer["QUERYABLE"] == "YES") : false), (layer["TYPE"] == "RADIO" ? layer["RADIO_GROUP"] : null), (layer["SERVER_LAYERS"] ? false : true), (layer["SERVER_LAYERS"] ? false : true), (layer["MINIMUM_RESOLUTION"] ? layer["MINIMUM_RESOLUTION"] : null), layer["DEPTH"], layer["REFRESH_SECONDS"], layer["LEGEND_COLOR"] ? layer["LEGEND_COLOR"] : null);
	}
}

function load_layers(reconstructing) {
	if (reconstructing) {
		// Reset layer visibilities
		layer_group_visibility = {};
		// Clear HTML editing space
		html_string = "";
	}
	layers = new Array();

	// Body-specific layers
	for (var layer_id in configuration["BODIES"][current_body]["LAYERS"]) {
		load_layer(layers, layer_id, configuration["BODIES"][current_body]["LAYERS"][layer_id], reconstructing);
	}
	// Universal layers
	for (var layer_id in configuration["UNIVERSAL_LAYERS"]) {
		load_layer(layers, layer_id, configuration["UNIVERSAL_LAYERS"][layer_id], reconstructing);
	}
	if (reconstructing) {
		// Hand the constructed dialog box to the HTML page
		jQuery("#lunaserv_layers").html(html_string);
	}

	var layer;
	for (layer = 0; layer < layers.length; layer++) {
		layers[layer].events.on({ loadstart: function () { active_tasks.push("get_a_layer"); document.getElementById("lunaserv_map").style.cursor = "wait"; }, loadend: function () { active_tasks.splice(active_tasks.indexOf("get_a_layer"), 1); if (active_tasks.length == 0) document.getElementById("lunaserv_map").style.cursor = cursor_string; } });
	}
	map.addLayers(layers);
	// Rearrange the layers, if need be
	for (var i = 1; i < layers.length; i++) {
		if (layers[i].depth) {
			map.setLayerIndex(layers[i], layers[i].depth);
		}
	}
}

function loadBboxDrawingLayer() {
	var bBoxLayer = new OpenLayers.Layer.Vector("Box layer");
	map.addLayer(bBoxLayer);
	map.addControl(new OpenLayers.Control.LayerSwitcher());
	//map.addControl(new OpenLayers.Control.MousePosition());
	bBoxDrawingControl = new OpenLayers.Control.DrawFeature(bBoxLayer,
		OpenLayers.Handler.RegularPolygon, {
		handlerOptions: {
			sides: 4,
			irregular: true
		}
	});

	map.addControl(bBoxDrawingControl);

	bBoxDrawingControl.events.register('featureadded', bBoxDrawingControl, click);

	if (jQuery('input[name=lunaserv_click_mode]:checked', '#bounding-box').val()) {
		jQuery("#point-of-interest").click();
	}
}

function getMdsParamObject() {
	var pObj = {};
	var params = window.location.href.split('?')[1];
	if (typeof params === 'undefined') return (null);
	params = params.split('&');
	for (var i = 0; i < params.length; i++) {
		pObj[params[i].split('=')[0]] = params[i].split('=')[1];
	}
	return (pObj);
}

function clear_mds(e) {
	if (browserIsIE) window.location.href = window.location.href.split('?')[0];
	else History.pushState(null, null, '/lunaserv.html');
	feature_fetcher.vendorParams["MDS_SEARCH"] = null;
	apply_mds_search(null);
	//jQuery('#mds_controls').hide();
}

function return_to_mds(e) {
	if (mdsParams === null) return (false);
	var mP = '';
	var keys = Object.keys(mdsParams);
	for (k in keys) {
		mP += (mP.length ? '&' : '?') + keys[k] + '=' + mdsParams[keys[k]];
	}
	window.location.href = configuration['MDS_URL'] + mP;
}

function init(lon_c, lat_c, different_body, check_for_permalink) {
	// If we're checking for a permalink, we need to load the right body and center the projection on the right spot (more permalink-checking is done later)
	if (check_for_permalink) {
		var projection = check_for_url_parameter("projection");
		if (projection != "") {
			document.getElementById("lunaserv_projection_switch_menu").value = projection;
			current_projection = projection;
		}
		var body = check_for_url_parameter("body");
		if (body != "") {
			document.getElementById("lunaserv_body_switch_menu").value = body;
			current_body = body;
		}
		var c_lon = check_for_url_parameter("c_lon");
		if (c_lon != "") {
			document.getElementById("lunaserv_lon_c").selectedIndex = round_number(parseFloat(c_lon), 3);
			lon_c = c_lon;
		}
		var c_lat = check_for_url_parameter("c_lat");
		if (c_lat != "") {
			document.getElementById("lunaserv_lat_c").selectedIndex = round_number(parseFloat(c_lat), 3);
			lat_c = c_lat;
		}
	}
	// Simply use the first WMS URL for feature fetchage
	feature_fetcher = new OpenLayers.Control.WMSGetFeatureInfo({ url: url_array[0], infoFormat: "text/html", maxFeatures: 10000 });
	var x_extent_length;
	var y_extent_length;
	var total_zoom_ratio; // What the ratio of resolution between max zoom and min zoom should be

	// Get the default basemap, body code, and radius for the current body
	var overview_basemap = configuration["BODIES"][current_body]["DEFAULT_BASEMAP"];
	var body_code = configuration["BODIES"][current_body]["BODY_CODE"];
	radius = configuration["BODIES"][current_body]["RADIUS"];

	// If we didn't get a lon_c / lat_c, use the default.  If the body does not specify a default, just use (0, 0).
	if (lon_c == null && lat_c == null) {
		lon_c = 0;
		lat_c = 0;
		if (configuration["BODIES"][current_body]["DEFAULT_CENTER"]) {
			lon_c = configuration["BODIES"][current_body]["DEFAULT_CENTER"].split(/[\s,]+/)[0];
			lat_c = configuration["BODIES"][current_body]["DEFAULT_CENTER"].split(/[\s,]+/)[1];
			finish_init(lon_c, lat_c, body_code, different_body, overview_basemap, check_for_permalink);
		}
		else {
			if (configuration["BODIES"][current_body]["DEFAULT_CENTER_URL"]) {
				jQuery.getJSON(configuration["BODIES"][current_body]["DEFAULT_CENTER_URL"], function (defaultCenter) {
					if (!defaultCenter.longitude.isNaN && !defaultCenter.latitude.isNaN) {
						lon_c = defaultCenter.longitude;
						lat_c = defaultCenter.latitude;
					}
					finish_init(lon_c, lat_c, body_code, different_body, overview_basemap, check_for_permalink);
				});
			}
			else {
				finish_init(lon_c, lat_c, body_code, different_body, overview_basemap, check_for_permalink);
			}
		}
	}
	else {
		finish_init(lon_c, lat_c, body_code, different_body, overview_basemap, check_for_permalink);
	}
}

function finish_init(lon_c, lat_c, body_code, different_body, overview_basemap, check_for_permalink) {
	var projection_code;
	var bbox;
	if (current_projection == "ORTHO") {
		// Add a little breathing room
		x_extent_length = radius * 5 / 4;
		y_extent_length = radius * 5 / 4;
		projection_code = "IAU2000:" + body_code + "66,9001," + lon_c + "," + lat_c;
		document.getElementById('lunaserv_recentering_controls').style.display = "";
		document.getElementById("lunaserv_lat_field").style.display = "";
		document.getElementById("lunaserv_lon_field").style.display = "";
		document.getElementById('lunaserv_lat_c').value = round_number(lat_c, 3);
		document.getElementById('lunaserv_lon_c').value = round_number(valid_longitude(lon_c), 3);
		total_zoom_ratio = 100;
	}
	if (current_projection == "SINU") {
		projection_code = "IAU2000:" + body_code + "60,9001," + lon_c;
		// We need very large extents for sinusoidal
		x_extent_length = radius * 4;
		y_extent_length = radius * 2;
		// In sinusoidal, latitude center is always 0
		document.getElementById('lunaserv_recentering_controls').style.display = "";
		document.getElementById("lunaserv_lat_field").style.display = "none";
		document.getElementById("lunaserv_lon_field").style.display = "";
		document.getElementById('lunaserv_lon_c').value = round_number(valid_longitude(lon_c), 3);
		total_zoom_ratio = 100;
	}
	if (current_projection == "NP_STEREO" || current_projection == "SP_STEREO") {
		projection_code = "IAU2000:" + body_code + (current_projection == "NP_STEREO" ? "18" : "20");
		// We need very small extents for stereographic to be reasonable
		x_extent_length = radius / 1.75;
		y_extent_length = radius / 1.75;
		// Stereographic has fixed center
		document.getElementById('lunaserv_recentering_controls').style.display = "none";
		total_zoom_ratio = 30;
	}
	if (current_projection == "2000") {
		projection_code = "IAU2000:" + body_code + "00";
		// This projection is just measured in lon/lat
		x_extent_length = 180;
		y_extent_length = 90;
		// Stereographic has fixed center
		document.getElementById('lunaserv_recentering_controls').style.display = "none";
		total_zoom_ratio = 100;
	}
	bbox = [-x_extent_length, -y_extent_length, x_extent_length, y_extent_length];
	var srs_bbox = "SRS=" + projection_code + "&BBOX=" + bbox[0] + "," + bbox[1] + "," + bbox[2] + "," + bbox[3];
	if (!overview_width) overview_width = document.getElementById("lunaserv_overview").clientWidth;
	overview_height = overview_width * y_extent_length / x_extent_length;
	document.getElementById("lunaserv_overview_map").src = url_array[0] + "?SERVICE=WMS&REQUEST=GetMap&LAYERS=" + overview_basemap + ",universal_overview_annotation&" + srs_bbox + "&VERSION=1.1.1&WIDTH=" + overview_width + "&HEIGHT=" + overview_height + "&TRANSPARENT=true&FORMAT=image/png";
	document.getElementById("lunaserv_overview_map").style.visibility = "hidden";
	document.getElementById("lunaserv_overview_loading").style.visibility = "visible";
	document.getElementById("lunaserv_overview_map").onload = function () {
		document.getElementById("lunaserv_overview_map").style.visibility = "visible";
		document.getElementById("lunaserv_overview_loading").style.visibility = "hidden";
		update_overview_box();
	}
	OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
	center_longitude = lon_c;
	center_latitude = lat_c;
	map = new OpenLayers.Map({ eventListeners: { "mousemove": mouse_move, "moveend": map_move }, tileSize: new OpenLayers.Size(512, 512), div: "lunaserv_map", maxExtent: new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]), minExtent: new OpenLayers.Bounds(bbox[0] / total_zoom_ratio, bbox[1] / total_zoom_ratio, bbox[2] / total_zoom_ratio, bbox[3] / total_zoom_ratio), restrictExtent: new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]), units: 'm', projection: projection_code, panDuration: 100, controls: [new OpenLayers.Control.Navigation({ dragPanOptions: { enableKinetic: true } }), new OpenLayers.Control.PanZoomBar({ zoomWorldIcon: true, slideRatio: 0.25 }), feature_fetcher] });

	// Click handler
	OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
		defaultHandlerOptions: {
			'single': true,
			'double': true,
			'pixelTolerance': 0,
			'stopSingle': true,
			'stopDouble': true
		},
		initialize: function (options) {
			this.handlerOptions = OpenLayers.Util.extend(
				{}, this.defaultHandlerOptions
			);
			OpenLayers.Control.prototype.initialize.apply(
				this, arguments
			);
			this.handler = new OpenLayers.Handler.Click(
				this, {
				//'click': this.trigger,
				'click': this.singleClickTrigger,
				'dblclick': this.trigger
			}, this.handlerOptions
			);
		},
		singleClickTrigger: function (e) {
			singleClick(e);
		},
		trigger: function (e) {
			click(e);
		}
	});
	var clickControl = new OpenLayers.Control.Click();
	map.addControl(clickControl);
	clickControl.activate();

	feature_fetcher.events.register("getfeatureinfo", feature_fetcher, show_info);

	document.getElementById('lunaserv_overview').onclick = function (e) {
		if (!e) e = window.event;
		var overview_map_offset = jQuery(document.getElementById('lunaserv_overview_map')).offset();
		var overview_map_left = overview_map_offset.left;
		var overview_map_top = overview_map_offset.top;
		var page_x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		var page_y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		var mouse_x = page_x - overview_map_left;
		var mouse_y = page_y - overview_map_top;
		var fraction_x = mouse_x / document.getElementById('lunaserv_overview_map').clientWidth;
		var fraction_y = mouse_y / document.getElementById('lunaserv_overview_map').clientHeight;
		var x = fraction_x * (map.getMaxExtent().right - map.getMaxExtent().left) + map.getMaxExtent().left;
		var y = fraction_y * (map.getMaxExtent().bottom - map.getMaxExtent().top) + map.getMaxExtent().top;
		var geo_location = unproject({ lon: x, lat: y });
		if (!isNaN(geo_location.lon) && !isNaN(geo_location.lat))
			recenter(valid_longitude(geo_location.lon), geo_location.lat, true, true);
	};

	// Load the layers, telling the function whether or not reconstruction of the layer selection box is necessary
	load_layers(!layer_group_visibility || different_body);

	map.zoomToMaxExtent();
	map.setCenter(new OpenLayers.LonLat(lon_c, lat_c));

	legend_remove_all(); // Make sure there are no left over legend entries.  Can occur during projection change.

	// If we're checking for a permalink, we need to recenter (panning-wise) and account for the layer selections
	if (check_for_permalink) {
		var x = check_for_url_parameter("x");
		var y = check_for_url_parameter("y");
		var resolution = check_for_url_parameter("resolution");
		if (x != "" && y != "") {
			map.setCenter(new OpenLayers.LonLat(parseFloat(x), parseFloat(y)));
		}
		if (resolution != "") map.zoomTo(map.getZoomForResolution(parseFloat(resolution), true));
		// Look at the 'layers' parameter
		var layer_ids = check_for_url_parameter("layers");
		if (layer_ids != "") {
			// Split by the comma
			layer_ids = layer_ids.split(",");
			// Turn them on
			for (var i = 0; i < layer_ids.length; i++) {
				document.getElementById("lunaserv_switch_" + layer_ids[i]).checked = true;
			}
		}
		refresh_layer_visibilities();
	}

	for (group in configuration["BODIES"][current_body]["LAYERS"]) { //turn on layers when coming from MDS based on indicators in URL
		g = Object.keys(configuration['BODIES'][current_body]["LAYERS"][group]);
		for (layer in Object.keys(configuration['BODIES'][current_body]["LAYERS"][group])) {
			var l = configuration['BODIES'][current_body]["LAYERS"][group][g[layer]];
			if (typeof (l) == 'object' && typeof (l['QUERYABLE']) != 'undefined' && l['QUERYABLE'] == 'YES') {
				if (!jQuery('#lunaserv_switch_' + g[layer]).is(':checked') && check_for_url_parameter(l['SERVER_LAYERS'] + '-includeInSearch') === 'true') {
					jQuery('#lunaserv_switch_' + g[layer]).prop('checked', true);
				}
			}
		}
	}

	if (check_for_url_parameter('MDS_SEARCH').length) {
		mdsParams = getMdsParamObject();
		apply_mds_search(check_for_url_parameter('MDS_SEARCH'));
	}

	refresh_layer_visibilities();

	loadBboxDrawingLayer();

	document.getElementById('lunaserv_scalebar').width = scale_bar_length;

	if (check_for_url_parameter('MDS_SEARCH').length) {
		jQuery('#lunaserv_clear_mds').click(clear_mds);
		jQuery('#lunaserv_return_to_mds').click(return_to_mds);
		jQuery('#mds_controls').show();
	}
	else {
		jQuery('#mds_controls').hide();
	}

	//default setting
	var lunaserv_body_select = document.getElementById("lunaserv_body_switch_menu").value;

	//get default basemap and layer id
	var default_basemap = configuration["BODIES"][current_body]["DEFAULT_BASEMAP"];
	var default_server_layer_id = "";
	if (default_basemap != null && default_basemap.length > 0) {
		default_server_layer_id = 'lunaserv_switch_' + default_basemap.toUpperCase();
	}
	if (lunaserv_body_select.toLowerCase() == 'mars') {
		//set default layer id
		if (jQuery("#" + default_server_layer_id).length > 0) {
			jQuery("#" + default_server_layer_id).click();
		}
		else if (jQuery("#lunaserv_switch_MARS_MOLA").length > 0) {
			jQuery("#lunaserv_switch_MARS_MOLA").click();
		}
		else if (jQuery("#lunaserv_switch_MARS_NOMENCLATURE").length > 0) {
			jQuery("#lunaserv_switch_MARS_NOMENCLATURE").click();
		}
	}
	else if (lunaserv_body_select.toLowerCase() == 'moon') {
		if (jQuery("#" + default_server_layer_id).length > 0) {
			jQuery("#" + default_server_layer_id).click();
		}
		// else if (jQuery("#lunaserv_switch_LUNA_CE1_DOM").length > 0) {
		// 	jQuery("#lunaserv_switch_LUNA_CE1_DOM").click();
		// }
		// else if (jQuery("#lunaserv_switch_LUNA_WAC_DTM").length > 0) {
		// 	jQuery("#lunaserv_switch_LUNA_WAC_DTM").click();
		// }
		// else if (jQuery("#lunaserv_switch_LUNA_NOMENCLATURE").length > 0) {
		// 	jQuery("#lunaserv_switch_LUNA_NOMENCLATURE").click();
		// }
	}
} // End of finish_init()

// Triggered whenever the browser window is resized
function window_got_resized() {
	// Reset maximum height of layer selection window and help message window
	jQuery('#lunaserv_layers').css('max-height', (jQuery(window).innerHeight() * .90));
	jQuery('#lunaserv_help_text').css('max-height', (jQuery(window).innerHeight() * .75));
}

function initializeHTMLafterPageLoad(resizable_map) {
	// Get the WMS server array
	url_array = new Array();
	for (var i = 0; i < configuration["WMS_URLS"].length; i++) url_array.push(configuration["WMS_URLS"][i]);

	// Add the bodies from the configuration to the dropdown menu, and select the default
	var bodies = 0;
	for (var body in configuration["BODIES"]) {
		bodies++;
		jQuery('#lunaserv_body_switch_menu').append('<option value="' + body + '">' + configuration["BODIES"][body]["NAME"] + '</option>');
	}
	// If only one body available, chuck the body-switching control
	if (bodies == 1) document.getElementById("lunaserv_body_switch_area").style.display = "none";
	document.getElementById("lunaserv_body_switch_menu").value = configuration["DEFAULT_BODY"];
	current_body = configuration["DEFAULT_BODY"];
	radius = configuration["BODIES"][current_body]["RADIUS"];

	// Fill the external container with the internal container
	jQuery('#lunaserv_container').height(external_container.innerHeight());
	jQuery('#lunaserv_container').width(external_container.innerWidth());

	// Default to window size
	if (jQuery('#lunaserv_container').width() == 0) jQuery('#lunaserv_container').css('width', jQuery(window).innerWidth());
	if (jQuery('#lunaserv_container').height() == 0) {
		// Get the absolute vertical offset of the container on the entire page
		var absolute_top = 0;
		var component = document.getElementById("lunaserv_container");
		while (component != null) {
			absolute_top += component.offsetTop;
			component = component.offsetParent;
		}
		jQuery('#lunaserv_container').css('height', jQuery(window).innerHeight() - absolute_top);
	}

	// Fill the internal container with the map
	jQuery('#lunaserv_map').height(jQuery('#lunaserv_container').innerHeight());
	jQuery('#lunaserv_map').width(jQuery(window).width());

	// Make the map view resizable if the caller asked for such
	if (resizable_map) jQuery('#lunaserv_map').resizable({ stop: function (event, ui) { map.updateSize(); } });

	// Make the feature container resizable, and adjust the top of its contents
	jQuery('#lunaserv_feature_container').resizable({ containment: "#lunaserv_container", minHeight: 300, minWidth: 300 });
	jQuery('#lunaserv_feature_close_icon').click(function () {//hide feature container when close icon is clicked
		jQuery('#lunaserv_feature_container').hide();
	});

	// And make the dialog boxes draggable
	jQuery('#lunaserv_feature_container').draggable({ handle: "div#lunaserv_features_titlebar", containment: '#lunaserv_container' });
	jQuery('#lunaserv_feature_container').on('drag', queryResultHeaderScrolling);
	jQuery('#lunaserv_feature_container').on('dragStop', queryResultHeaderScrolling);
	//jQuery('#lunaserv_feature_container').on('rserv_features_titlebaresize', queryResultHeaderScrolling);
	jQuery('#lunaserv_feature_container').on('resize', queryResultHeaderScrolling);

	if (jQuery(window).innerHeight() < jQuery('#lunaserv_map_controls').height())
		alert("Browser window is too small to contain 'Map Options' window. Operational problems may be encountered.  Please increase browser window size and press refresh button");
	// Go ahead and trigger the window-resize effects, for the initial load
	window_got_resized();
	jQuery(window).resize(window_got_resized);

	init(null, null, false, true);

    // 折叠功能实现 - 通过监听父窗口消息控制
    jQuery(document).ready(function() {
        const accordion = jQuery('#accordion');
        const scaleBar = jQuery('#scale_bar');
        // 定义动画持续时间，确保按钮和侧边栏动画同步
        const animationDuration = 300;
        // 定义导航栏宽度
        const sidebarWidth = 400;

        // 初始化状态 - 确保导航栏初始可见
        accordion.css('left', '0px');
        accordion.removeClass('collapsed');
        
        // 监听来自父窗口的消息
        window.addEventListener('message', function(event) {
            // 确保消息来源安全（可选）
            // if (event.origin !== window.location.origin) return;
            
            if (event.data && event.data.type === 'TOGGLE_SIDEBAR') {
                if (accordion.hasClass('collapsed')) {
                    // 展开导航栏
                    accordion.animate({'left': '0px'}, animationDuration, function() {
                        accordion.removeClass('collapsed');
                    });
                    // 调整经纬度显示位置
                    scaleBar.animate({'left': '410px'}, animationDuration);
                } else {
                    // 收缩导航栏
                    accordion.animate({'left': '-' + sidebarWidth + 'px'}, animationDuration, function() {
                        accordion.addClass('collapsed');
                    });
                    // 调整经纬度显示位置
                    scaleBar.animate({'left': '10px'}, animationDuration);
                }
            }
        });
    });

	jQuery('input').on('change', function () {
		if (jQuery('input[name=lunaserv_click_mode]:checked', '#point-of-interest').val()) {
			jQuery('#point-of-interest').css('background', 'url("../images/crosshairs.png") no-repeat left top');
			jQuery('#get-footprint').css('background', 'url("../images/eye-gray.png") no-repeat left top');
			jQuery('#bounding-box').css('background', 'url("../images/bounding-gray.png") no-repeat left top');
			jQuery('#lunaserv_map').css('cursor', 'default');
			if (bBoxDrawingControl != null) {
				bBoxDrawingControl.deactivate();
			}
		}

		if (jQuery('input[name=lunaserv_click_mode]:checked', '#get-footprint').val()) {
			jQuery('#get-footprint').css('background', 'url("../images/eye-white.png") no-repeat left top');
			jQuery('#point-of-interest').css('background', 'url("../images/crosshairs-gray.png") no-repeat left top');
			jQuery('#bounding-box').css('background', 'url("../images/bounding-gray.png") no-repeat left top');
			jQuery('#lunaserv_map').css('cursor', 'help');
			if (bBoxDrawingControl != null) {
				bBoxDrawingControl.deactivate();
			}
		}

		if (jQuery('input[name=lunaserv_click_mode]:checked', '#bounding-box').val()) {
			jQuery('#get-footprint').css('background', 'url("../images/eye-gray.png") no-repeat left top');
			jQuery('#point-of-interest').css('background', 'url("../images/crosshairs-gray.png") no-repeat left top');
			jQuery('#bounding-box').css('background', 'url("../images/bounding-white.png") no-repeat left top');
			jQuery('#lunaserv_map').css('cursor', 'crosshair');
			if (bBoxDrawingControl != null) {
				bBoxDrawingControl.activate();
			}
		}
	});

	jQuery(".lunaserv_text_entry_item .input-daterange").datepicker({});
	jQuery("#point-of-interest").click();
	// Prevent dragging of Query Results on mobile so that results can be navigated with thumb
	if (jQuery(window).width() <= 620) {
		jQuery('.lunaserv_controls').draggable('disable');
	}

	// Other events
	jQuery('#lunaserv_recenter_button').click(function (event) {
		invoke_recenter();
	});

	jQuery('#lunaserv_lat_c').keypress(function (event) {
		checkNumeric(event);
	});

	jQuery('#lunaserv_lon_c').keypress(function (event) {
		checkNumeric(event);
	});

	jQuery('#lunaserv_lat_c').blur(function (event) {
		if (jQuery('#lunaserv_lat_c').val() >= -90 && jQuery('#lunaserv_lat_c').val() <= 90) {
			jQuery('#lunaserv_lat_c_err').html('');
			lat_err = false;
		}
		else {
			event.preventDefault();
			jQuery('#lunaserv_lat_c_err').html('Valid latitudes are -90 thru +90'.fontcolor("red"));
			jQuery('#lunaserv_lat_c').trigger('focus');
			lat_err = true;
		}
	});

	jQuery('#lunaserv_lon_c').blur(function (event) {
		if (jQuery('#lunaserv_lon_c').val() >= -180 && jQuery('#lunaserv_lon_c').val() <= 360) {
			jQuery('#lunaserv_lon_c_err').html('');
			lon_err = false;
		}
		else {
			event.preventDefault();
			jQuery('#lunaserv_lon_c_err').html('Valid longitudes are -180 thru +360'.fontcolor("red"));
			jQuery('#lunaserv_lon_c').trigger('focus');
			lon_err = true;
		}
	});
	if (!browserIsIE) History.Adapter.bind(window, 'statechange', function () { init(null, null, false, true) }); //Run init() again when 'state' of url changes.  If we don't it doesn't change the layers, etc.
	init_tour();
	tour.start();
}

function distance(point, p) {
	var distance = Math.sqrt(Math.pow(point.x - p.x, 2) + Math.pow(point.y - p.y, 2));
	return distance;
}

function singleClick(event) {
	if(jQuery('input[id="lunaserv_switch_LUNA_NOMENCLATURE"]:checked').length == 0 &&
	 jQuery('input[id="lunaserv_switch_MARS_NOMENCLATURE"]:checked').length == 0){
		return;
	}

	var new_location = map.getLonLatFromPixel(event.xy);
	var coords = unproject(new_location);

	var lunaserv_body_select = document.getElementById("lunaserv_body_switch_menu").value;
	var features;
	if (lunaserv_body_select.toLowerCase() == 'mars') {
		features = lroc_nomenclature_mars_geo.features;
	}
	else if (lunaserv_body_select.toLowerCase() == 'moon') {
		features = lroc_nomenclature_moon_geo.features;
	}

	if (!isNaN(coords.lon) && !isNaN(coords.lat)) {
		var lonlat = new OpenLayers.LonLat(coords.lon, coords.lat);
		var size = new OpenLayers.Size(440, 550);

		var point = { x: coords.lat, y: coords.lon };
		var points = [];
		//TODO init
		jQuery.each(features, function (index, value) {
			points.push({ x: value.properties.lat, y: valid_longitude(value.properties.lon), feature: value });
		});

		if (points.length == 0) { return };

		// closestFeature = points.reduce((a, b) => distance(point, a) < distance(point, b) ? a : b);
		// if (distance(point, closestFeature) > 4) {
		// 	return;
		// }

		closestFeature = points.reduce(function(prev, cur){
			return distance(point, prev) < distance(point, cur) ? prev : cur
		});
		if (distance(point, closestFeature) > 4) {
			return;
		}

		var content = getPopupContent(closestFeature.feature);
		var popup = new OpenLayers.Popup.Anchored('divPopup', lonlat, size, content, null, true, null);
		popup.offset = new OpenLayers.Pixel(0, 0);
		var popups = map.popups;
		for (var i = 0; i < popups.length; i++) {
			popups[i].destroy();
		}

		popup.calculateNewPx = function (px) {
			if (popup.size !== null) {
				px = px.add(px.x * -1, px.y * -1);
			}
			return px;
		};

		map.addPopup(popup);
		//z-index 重新赋值，确保在最上层
		map.popups[0].events.element.style.zIndex = 9999;
		map.popups[0].events.element.style.backgroundColor = "TRANSPARENT";
	}
	else {
		var popups = map.popups;
		for (var i = 0; i < popups.length; i++) {
			popups[i].destroy();
		}
	}

	jQuery(".popup-portal").click(function (clickEvent) {
		//popup之外点击，则div消失
		if (isInDiv(clickEvent, "popup-content")) {
			return;
		}

		//popup dispose
		for (var i = 0; i < popups.length; i++) {
			popups[i].destroy();
		}
	});
}

function isInDiv(event, divId) {
	var div = jQuery("#" + divId);
	var x = event.clientX;
	var y = event.clientY;

	var x1 = div.offset().left;
	var y1 = div.offset().top;
	var x2 = x1 + div.outerWidth(true);
	var y2 = y1 + div.outerHeight(true);

	return x > x1 && x < x2 && y > y1 && y < y2;
}

function getPopupContent(geoFeature) {
	var str = '<div class="popup-portal">'
		+ '<div class="popup-overlay">'
		+ '<div class="popup-content" id="popup-content" tabindex="-1" role="dialog" aria-label="Query Modal">'
		+ '<h1 style="margin-top: 0px;">'
		+ '<div class="cJKwwR">详细信息</div>'
		+ '</h1>'
		+ '<div class="bLTWri">';
	if (geoFeature.properties.cname != undefined &&
		geoFeature.properties.cname.length > 0) {
		str += '<div class=" kadBmb">中文名称</div>'
			+ '<div class=" kxaiRq">' + geoFeature.properties.cname + '</div>';
	}

	str += '<div class=" kadBmb">英文名称</div>'
		+ '<div class=" kxaiRq">' + geoFeature.properties.ename + '</div>'
		+ '<div class=" kadBmb">经度</div>'
		+ '<div class=" kxaiRq">' + geoFeature.properties.lon + '</div>'
		+ '<div class=" kadBmb">纬度</div>'
		+ '<div class=" kxaiRq">' + geoFeature.properties.lat + '</div>';

	if (geoFeature.properties.link != undefined &&
		geoFeature.properties.link.length > 0) {
		str += '<div class=" kadBmb">链接</div>'
			+ '<div class=" kxaiRq">'
			+ '<a target="_blank" rel="noopener noreferrer"'
			+ 'href="' + geoFeature.properties.link + '">全景图</a>'
			+ '</div>';
	}

	str += '</div>'
		+ '</div>'
		+ '</div>'
		+ '</div>';
	return str;
}

(function (jQuery) {
	jQuery.fn.lunaserv_interface = function (resizable_map, config_file, html_content_file) {

		// Denote the containing page's container for the map (the object upon which this plugin should
		// be called) as the external_container
		external_container = this;

		// Stuff to do at page load
		jQuery(document).ready(function () {

			// Load the HTML content for the container
			jQuery.get(html_content_file, function (html_content) {
				jQuery(external_container).html(html_content);

				// Load the configuration
				jQuery.get(config_file, function (cnfgFile) {
					configuration = jsyaml.load(cnfgFile);
					initializeHTMLafterPageLoad(resizable_map);
				}, 'text')
					.fail(function (err) {
						alert('An error ocurred while loading config file: "' + config_file + '"\n\nError: ' + err.status + ' - ' + err.statusText);
					});
			}, 'html')
				.fail(function (err) {
					alert('An error ocurred while loading HTML content file: "' + html_content_file + '"\n\nError: ' + err.status + ' - ' + err.statusText);
				});
		});
		init_layer_desc();
	}

})(jQuery);

/************************\
| Compatibility for IE 8 |
\************************/

// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
	Array.prototype.map = function (callback, thisArg) {

		var T, A, k;

		if (this == null) {
			throw new TypeError(" this is null or not defined");
		}

		// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
		var O = Object(this);

		// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
		// 3. Let len be ToUint32(lenValue).
		var len = O.length >>> 0;

		// 4. If IsCallable(callback) is false, throw a TypeError exception.
		// See: http://es5.github.com/#x9.11
		if ({}.toString.call(callback) != "[object Function]") {
			throw new TypeError(callback + " is not a function");
		}

		// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
		if (thisArg) {
			T = thisArg;
		}

		// 6. Let A be a new array created as if by the expression new Array(len) where Array is
		// the standard built-in constructor with that name and len is the value of len.
		A = new Array(len);

		// 7. Let k be 0
		k = 0;

		// 8. Repeat, while k < len
		while (k < len) {

			var kValue, mappedValue;

			// a. Let Pk be ToString(k).
			//   This is implicit for LHS operands of the in operator
			// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
			//   This step can be combined with c
			// c. If kPresent is true, then
			if (k in O) {

				// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
				kValue = O[k];

				// ii. Let mappedValue be the result of calling the Call internal method of callback
				// with T as the this value and argument list containing kValue, k, and O.
				mappedValue = callback.call(T, kValue, k, O);

				// iii. Call the DefineOwnProperty internal method of A with arguments
				// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
				// and false.

				// In browsers that support Object.defineProperty, use the following:
				// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });

				// For best browser support, use the following:
				A[k] = mappedValue;
			}
			// d. Increase k by 1.
			k++;
		}

		// 9. return A
		return A;
	};
}

function init_layer_desc() {
	//LROC 广角相机全球拼接图
	layer_desciption["desc_luna_wac_global"] = '该图层为月球全球拼接图，由月球勘察轨道器(Lunar Reconnaissance Orbiter, LRO)搭载的宽角相机(Wide Angle Camera, WAC)拍摄的图像拼接而成，展示了月球表面的地形地貌特征，分辨率为100米。月球勘察轨道器相机(Lunar Reconnaissance Orbiter Camera, LROC)由三台相机组成，两台窄角相机(narrow-angle cameras, NACs)和一台宽角相机(WAC)。图像来源：NASA/ASU';
	//LROC 假彩色高程图
	layer_desciption["desc_luna_wac_dtm"] = '该图层为月球全球的山体阴影晕渲伪彩色图，由月球勘察轨道器(Lunar Reconnais-sance Orbiter, LRO)搭载的宽角相机(Wide Angle Camera, WAC)拍摄的立体像对(Stereo Image)，经过“晕渲法”处理获得的山体阴影图。其中，不同色彩表示当地的高程信息。来源：NASA/ASU'+
											'<br>图例：<br>' +
											'<img src="/images/LROCDTMSCALE-MOON.jpg">';//TODO
	//Clementine全球拼接图
	layer_desciption["desc_luna_clementine_750nm"] = '该图层为Clementine反照率全球拼接图，表示由紫外/可见光（UVVIS）相机在750纳米（nm）波长下测量的反照率（月球表面的亮度），分辨率为每像素118米。来源：USGS';
	//嫦娥1号全球拼接图
	layer_desciption["desc_luna_ce1dom120m"] = '该图层为月球全球的数字正射影像图(Digital Orthophoto Map, DOM)，由我国嫦娥一号卫星上搭载的CCD立体相机在约200公里轨道高度上获取的月面影像数据制作。分辨率为120米。来源：中国航天局';
	//月球全球地质图
	layer_desciption["desc_luna_geology"] = '该图层为月球全球地质图，比例尺为1:5,000,000。彩色地质单元图展示了月球表面的主要地质地貌特征，包括：月海(Mare)，月溪(Rima)，坑链(Catena)，环形山脊(Dorsum)，山脊(Dorsa)，山脉(Montes)等。'

	//Viking 全球彩色图
	layer_desciption["desc_mars_viking"] = '该图层是火星全球彩色拼接图，利用Viking 1(海盗1号)和Viking 2(海盗2号)轨道探测器拍摄的红光和紫光滤镜图像拼接而成的，展示了火星表面的地质地貌特征。图像来源：NASA';
	//THEMIS 日间红外全球拼接图
	layer_desciption["desc_mars_themisday"] = '该图层为火星全球白天热红外图像，利用火星“奥德赛”(Odyssey)航天器搭载的热发射成像系统(Thermal Emission Imaging System, THEMIS)所拍摄的白天影像拼接而成，图像分辨率为100米。THEMIS有五个可见光波段成像系统和九个红外波段成像系统，此拼接图即对红外波段的图像处理所得。图中显示的不同灰度级别，代表当地的温度，越亮的地方温度越高。图像来源：NASA/ASU';
	//THEMIS 夜间红外全球拼接图
	layer_desciption["desc_mars_themisnight"] = '该图层为火星夜间全球热红外图像，利用火星“奥德赛”(Odyssey)航天器搭载的热发射成像系统(Thermal Emission Imaging System, THEMIS)所拍摄的白天影像拼接而成，图像分辨率为100米。图中显示的不同灰度级别，代表当地的温度，越亮的地方温度越高。图像来源：NASA/ASU';
	//MOLA 假彩色高程地形图
	layer_desciption["desc_mars_mola"] = '该图层所展示的为火星全球高程的伪彩色图像，利用火星全球勘察者( Mars Global Surveyor, MGS)搭载的火星轨道激光高度计(Mars Orbiter Laser Altimeter, MOLA)获取的全球高程数据经过插值等处理后形成的图像。图像中显示的不同颜色，代表不同的高程级别，红色端高程较高，蓝色端高程较低。来源：NASA' +
										'<br>彩色比例尺图例：<br>' +
										'<img src="/images/MOLASCALE-MARS.jpg">';//TODO
    //TES 全球反射率拼接图
	layer_desciption["desc_mars_tes_albedo"] = '该图层为火星全球辐射测量反照率图像，利用火星全球勘察者( Mars Global Surveyor, MGS)搭载的热发射光谱仪(Thermal Emission Spectrometer, TES)所获取的观察数据得到。图像分辨率为7410米。图像来源：USGS';
	//CTX全球拼接图（局部）之中国2020火星任务预选着陆区
	layer_desciption["desc_mars_ctx"] = '该图层为火星全球的高分辨率图像，由火星勘察轨道器(Mars Reconnaissance Orbiter, MRO) 搭载的Context Camera(CTX)拍摄，分辨率为6 米。来源：NASA/MSSS/Caltech';
	//CTX全球拼接图（局部）之中国宇航局“毅力号”火星车着陆区
	layer_desciption["desc_mars_ctx_usa"] = 'Jezero 撞击坑（中心坐标  18.38°N 77.58°E）是发育三角洲的古湖泊，是寻找火星过去生命痕迹的理想地点之一。来源：NASA/MSSS/Caltech';
	//CTX全球拼接图（局部）之 Ares Vallis
	layer_desciption["desc_mars_ctx_aresvallis"] = '介绍写《行星地质学导论》课程用数据。';
	//火星全球地质图
	layer_desciption["desc_mars_geology"] = '该图层为火星全球地质图，展示了不同时代的各地质单元，包括：诺亚纪(Noachian)，西方纪(Hesperian)，亚马逊纪(Amazonian)。图中展示的地质单元包括：高地(Terra)，撞击坑(Crater)，混沌(Chaos，即地形复杂，多种地貌交织)，峡谷(Valles)，河谷(Vallis)，平原(Planitia)等。来源：USGS';
	//火星重力图
	layer_desciption["desc_mars_marsgravity"] = '该图层为火星重力场分布说明,利用了 Mars Global Surveyor (MGS), Mars Odyssey (ODY) 和 Mars Reconnaissance Orbiter (MRO)三个探测器的数据。由于火星表面本身凹凸不平，当探测器在上空掠过时所受的重力就会发生微弱的改变，这帮助研究者分析火星表面重力情况。研究人员使用重力加速度表示重力的分布情况，紫色和蓝色表示重力引起的加速度低于平均值的区域，而红色和白色表示重力加速度较高的区域。本数据通过来源：https://commons.wikimedia.org/wiki/File:GMM-3_Free_air_gravity_anomaly.jpg';
	//火星构造形迹
	layer_desciption["desc_mars_tectonic"] = '这些构造形迹大都形成于萨希斯火山以及巨型撞击盆地(如克里塞(Chryse)、 阿吉尔、海拉斯、伊斯迪斯)之前。萨希斯和艾丽丝米火山岩省(暗红色区域)、南部高原与平原的界线(橘红色虚线)、海岸线(红色实线)、岩石圈-地壳构造脆弱带(白色虚线)、伸展和挤压构造(黑色线)、大型撞击盆地( 黑色虚线圈闭区)、坦佩( Tempe)和塔玛西亚( Thaumasia)火山高原(橙色线)、萨希斯火山岩浆形成的构造区(不同的紫色区)、火山隆起(封闭的近圆形红色区域)、溢流河道( 蓝色线)和萨希斯火山区的盆地与水系( 蓝色虚线)(据Fairen & Dohm, 2004)';
	//火星磁场
	layer_desciption["desc_mars_magnetism"] = '火星地壳磁场，数据源于火星全球勘探者，MGS'+
		'<img src="/images/labelmagnetism.jpg">';
	//火星CTX全球图
	layer_desciption["desc_mars_ctxgm"] = '该图层来自CTX全球数据';
	//火星河谷网络图
	layer_desciption["desc_mars_valleynetwork"] = '该图层为火星河谷网络分布情况示意图。利用THEMISR日间红外,CTX图像与MOLA高程数据手动绘制。详情请查看：Alemanno, G., Orofino, V., & Mancarella, F. (2018). Global map of Martian fluvial systems: Age and total eroded volume estimations. Earth and Space Science, 5(10), 560-577。来源：https://zenodo.org/record/1051038#.Y1FC-2qHpPZ';
	//hirise
	layer_desciption["desc_mars_hirise"] = '高分辨率成像科学设备（英语：High Resolution Imaging Science Experiment，缩写为HiRISE）是火星探测卫星火星侦察轨道器的摄影机。该摄影机重量65kg，造价4000万美元，在亚利桑那大学的月球与行星实验室主导下由波尔航太科技公司（Ball Aerospace and Technologies Corp.）制造。该仪器包含一台口径0.5米的反射望远镜，是深太空任务中使用过最大的望远镜。该望远镜可拍摄分辨率达0.3米的火星表面影像。来源：NASA/UA';
	//HiRISE数据矢量位置
	layer_desciption["desc_mars_hirisefoots"] = '该图层为火星勘察轨道器(Mars Reconnaissance Orbiter, MRO)搭载的高分辨率相机(High Resolution Imaging Science Experiment, HiRISE)所拍摄影像的覆盖范围矢量图，数据来源于Mars ODE。';
	//天问一号中分辨率相机全球拼接图
	layer_desciption["desc_mars_moric_global"] = '首次火星探测任务地面应用系统公开发布天问一号中分辨率相机火星全球彩色影像图、中分辨率相机火星全球彩色影像分幅图，其分辨率为76米。';
}

function add_layer_desc(layer) {
	return layer_desciption[layer["DESCRIPTION"]] != undefined ? '<div class="ecCryF"><div>'
		+ layer_desciption[layer["DESCRIPTION"]]
		+ '</div></div>' : '';
}

jQuery(document).ready(function () {
	jQuery('#map_viewer').lunaserv_interface(true, 'config/lunaserv.yml?reload=1', 'templates/lunaserv_content.html');
});
